package com.handinglian.employee.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.handinglian.common.enums.ValidEnum;
import com.handinglian.common.exception.BizException;
import com.handinglian.common.utils.FastJsonUtil;
import com.handinglian.employee.dto.DepartmentDto;
import com.handinglian.employee.dto.DepartmentLevelDto;
import com.handinglian.employee.dto.DepartmentUserNumDto;
import com.handinglian.employee.dto.UserInfoDto;
import com.handinglian.employee.entity.Department;
import com.handinglian.employee.mapper.DepartmentMapper;
import com.handinglian.employee.param.DepartmentCreateParam;
import com.handinglian.employee.param.DepartmentUpdateParam;
import com.handinglian.employee.service.DepartmentService;
import com.handinglian.employee.service.UserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service("departmentService")
public class DepartmentServiceImpl implements DepartmentService {
    @Autowired
    private DepartmentMapper departmentMapper;
    @Autowired
    @Lazy
    private UserInfoService userInfoService;

    @Override
    @Transactional
    public int createDepartment(DepartmentCreateParam departmentCreateParam) {
        Date now = new Date();
        Department department = FastJsonUtil.ObjectToObject(departmentCreateParam, Department.class);
        department.setCreateTime(now);
        department.setUpdateTime(now);
        department.setOrderNo(9999);
        department.setValid(ValidEnum.VALID.getKey());
        return departmentMapper.insertSelective(department);
    }

    @Override
    public Department loadInvalidDepartment(String departmentName) {
        return departmentMapper.findInvalidOneByDepartmentName(departmentName);
    }

    @Override
    @Transactional
    public int recoverDepartment(String departmentName) {
        Department department = departmentMapper.findInvalidOneByDepartmentName(departmentName);
        department.setValid(ValidEnum.VALID.getKey());

        return departmentMapper.updateByPrimaryKeySelective(department);
    }

    @Override
    @Transactional
    public int updateDepartment(DepartmentUpdateParam departmentUpdateParam) {
/*        List<Integer> fiveLevelDepartmentIds = inquireFiveLevelDepartmentIds();
        if (fiveLevelDepartmentIds.size() > 0
                &&fiveLevelDepartmentIds.contains(departmentUpdateParam.getParentId())){
            throw BizException.DEPARTMENT_LEVEL_OUT;
        }*/
        Department department = FastJsonUtil.ObjectToObject(departmentUpdateParam, Department.class);
        department.setUpdateTime(new Date());
        return departmentMapper.updateByPrimaryKeySelective(department);
    }

    @Override
    @Transactional
    public int deleteDepartment(Integer departmentId) {
        List<UserInfoDto> userInfoDtos = userInfoService.inquireUserInfoByDepartmentId(departmentId, null);
        if (userInfoDtos.size() > 0){
            throw BizException.DEPARTMENT_EXIST_USER;
        }
        return departmentMapper.deleteByPrimaryKey(departmentId);
    }

    @Override
    public DepartmentDto loadDepartment(Integer departmentId) {
        Department department = departmentMapper.selectByPrimaryKey(departmentId);
        return FastJsonUtil.ObjectToObject(department, DepartmentDto.class);
    }

    @Override
    public List<DepartmentDto> inquireDepartmentList() {
        //各部门用户数量
        List<DepartmentUserNumDto> departmentUserNumDtos = departmentMapper.inquireDepartmentUserNum();

        List<DepartmentDto> departmentOneLevelDto = inquireDepartmentByParentId(CollUtil.newArrayList(0), departmentUserNumDtos);
        List<Integer> departmentIds = departmentOneLevelDto.stream().map(departmentDto -> departmentDto.getDepartmentId()).collect(Collectors.toList());
        updateDepartmentDto(departmentIds, departmentOneLevelDto, departmentUserNumDtos);
        return departmentOneLevelDto;
    }

    private void updateDepartmentDto(List<Integer> parentIds, List<DepartmentDto> parentDepartmentDto, List<DepartmentUserNumDto> departmentUserNumDtos){
        List<DepartmentDto> departmentDtos = inquireDepartmentByParentId(parentIds, departmentUserNumDtos);
        List<Integer> departmentIds = departmentDtos.stream().map(departmentDto -> departmentDto.getDepartmentId()).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(departmentIds)){
            for (DepartmentDto departmentDto : parentDepartmentDto){
                for (DepartmentDto departmentSubDto : departmentDtos){
                    if (departmentDto.getDepartmentId().equals(departmentSubDto.getParentId())){
                        departmentDto.addDepartment(departmentSubDto);
                    }
                }
            }
            updateDepartmentDto(departmentIds, departmentDtos, departmentUserNumDtos);
        }
    }

    @Override
    public List<Department> listSubDepartmentId(Integer departmentId) {
        Department departmentOneLevel = departmentMapper.selectByPrimaryKey(departmentId);
        List<Department> allDepartment = new ArrayList<>();
        allDepartment = listByParentId(CollUtil.newArrayList(departmentId), allDepartment);
        allDepartment.add(departmentOneLevel);
        return allDepartment;
    }

    private List<Department> listByParentId(List<Integer> parentIds, List<Department> allDepartment){
        List<Department> departments = departmentMapper.findByParentIdIn(parentIds);
        List<Integer> departmentIds = departments.stream().map(department -> department.getDepartmentId()).collect(Collectors.toList());
        allDepartment.addAll(departments);
        if (departmentIds.size() > 0){
            listByParentId(departmentIds, allDepartment);
        }
        return allDepartment;
    }

    @Override
    public List<DepartmentDto> inquireDepartmentByParentId(List<Integer> parentIds, List<DepartmentUserNumDto> departmentUserNumDtos) {
        if (parentIds.size() == 0){
            return new ArrayList<>();
        }
        List<Department> departments = departmentMapper.findByParentIdIn(parentIds);

        List<DepartmentDto> departmentDtos = FastJsonUtil.ListToList(departments, DepartmentDto.class);
        for (DepartmentDto departmentDto : departmentDtos){
            for (DepartmentUserNumDto departmentUserNumDto : departmentUserNumDtos){
                if (departmentUserNumDto.getDepartmentId().equals(departmentDto.getDepartmentId())){
                    departmentDto.setUserNum(departmentUserNumDto.getUserNum());
                    break;
                }
            }
        }
        return departmentDtos;
    }

    @Override
    public List<Department> listDepartment(List<Integer> parentIds) {
        if (parentIds.size() == 0){
            return new ArrayList<>();
        }
        return departmentMapper.findByParentIdIn(parentIds);
    }

    @Override
    public int updateOrderNo(List<Integer> updatedOrderNos, List<Integer> departmentIds) {
        int amount = 0;
        for (int i = 0;i < departmentIds.size();i++){
            amount = amount + departmentMapper.updateOrderNoByDepartmentId(updatedOrderNos.get(i), departmentIds.get(i));
        }
        return amount;
    }

    @Override
    public List<Department> listTwoLevelDepartment() {
        return listDepartment(CollUtil.newArrayList(1));
    }

    @Override
    public List<DepartmentLevelDto> listThreeLevelDepartment() {
        List<Department> twoLevelDepartments = listTwoLevelDepartment();
        List<Integer> twoLevelDepartmentId = twoLevelDepartments.stream().map(department -> department.getDepartmentId()).collect(Collectors.toList());
        List<Department> threeLevelDepartment = listDepartment(twoLevelDepartmentId);
        List<DepartmentLevelDto> departmentLevelDtos = FastJsonUtil.ListToList(threeLevelDepartment, DepartmentLevelDto.class);
        departmentLevelDtos.forEach(departmentLevelDto -> {
            twoLevelDepartments.forEach(twoLevelDepartment -> {
                if (departmentLevelDto.getParentId().equals(twoLevelDepartment.getDepartmentId())){
                    departmentLevelDto.setParentName(twoLevelDepartment.getDepartmentName());
                }
            });
        });
        return departmentLevelDtos;
    }

    @Override
    public List<Department> inquireDepartmentByDepartmentName(Collection<String> departmentNameCollection) {
        return departmentMapper.findByDepartmentNameIn(departmentNameCollection);
    }

    @Override
    public List<Department> getAll() {
        return departmentMapper.find();
    }
}
